﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web.Compilation;
using AspNetInfo.Detectors;
using AspNetInfo.Diagnostics;

namespace AspNetInfo.Core
{
    /// <summary>
    /// Search all assemblies in GAC and bin folder for classes that implement IDetector and ITestFixture.
    /// </summary>
    public class PluginProvider : IPluginProvider
    {
        private IEnumerable<IDetector> detectors;
        private IEnumerable<ITestFixture> diagnostics;

        public IEnumerable<IDetector> GetDetectorPlugins()
        {
            if (detectors == null)
                detectors = InitializeDetectorPlugins();
            return detectors;
        }

        public IEnumerable<ITestFixture> GetDiagnosticPlugins()
        {
            if (diagnostics == null)
                diagnostics = InitializeDiagnosticPlugins();
            return diagnostics;
        }

        /// <summary>
        /// Search all assemblies in GAC and bin folder for classes that implement the given type parameter
        /// </summary>
        /// <typeparam name="T">Plug-in type to search for</typeparam>
        /// <returns>A list of types that are supported by T</returns>
        private static IEnumerable<Type> FindPlugins<T>()
        {
            var type = typeof(T);
            return BuildManager.GetReferencedAssemblies().OfType<Assembly>().ToList()
                .SelectMany(s => s.GetTypes())
                .Where(p => type.IsAssignableFrom(p) && p.IsClass && p.Name != "TestFixture");
        }

        private static IEnumerable<ITestFixture> InitializeDiagnosticPlugins()
        {
            var fixtures = new List<ITestFixture>();
            var pluginTypes = FindPlugins<ITestFixture>();

            foreach (var plugin in pluginTypes)
            {
                var fixture = (ITestFixture)Activator.CreateInstance(plugin);
                fixtures.Add(fixture);
            }

            return fixtures;
        }

        private static IEnumerable<IDetector> InitializeDetectorPlugins()
        {
            var detectors = new List<IDetector>();
            var pluginTypes = FindPlugins<IDetector>();
            foreach (var plugin in pluginTypes)
            {
                detectors.Add((IDetector)Activator.CreateInstance(plugin));
            }
            return detectors;
        }
    }
}